//
// Created by entaoyang@163.com on 2021/8/2.
//

import Foundation

public extension Array where Element: Hashable {
    var toHashSet: HashSet<Element> {
        HashSet(self)
    }
}


public final class HashSet<Element: Hashable>: ExpressibleByArrayLiteral,
        Sequence, Collection, Equatable, Hashable, CustomReflectable,
        CustomStringConvertible, CustomDebugStringConvertible, SetAlgebra {


    public typealias ArrayLiteralElement = Element
    public typealias Indices = DefaultIndices<Set<Element>>
    public typealias SubSequence = Slice<Set<Element>>

    fileprivate var innerSet: Set<Element> = []

    var toSet: Set<Element> {
        self.innerSet
    }

    public init() {
        innerSet.reserveCapacity(16)
    }

    public init(capacity: Int) {
        innerSet.reserveCapacity(capacity)
    }

    public init(arrayLiteral elements: Element...) {
        innerSet.reserveCapacity(elements.count + 1)
        for e in elements {
            innerSet.add(e)
        }
    }


    public init(from decoder: Decoder) throws where Element: Decodable {
        innerSet = try Set(from: decoder)
    }

    public func encode(to encoder: Encoder) throws where Element: Encodable {
        try innerSet.encode(to: encoder)
    }

    public func makeIterator() -> Set<Element>.Iterator {
        innerSet.makeIterator()
    }

    public func contains(_ member: Element) -> Bool {
        innerSet.contains(member)
    }

    public func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> Set<Element> {
        try innerSet.filter(isIncluded)
    }


    public var startIndex: Set<Element>.Index {
        self.innerSet.startIndex
    }

    public var endIndex: Set<Element>.Index {
        self.innerSet.endIndex
    }

    public subscript(position: Set<Element>.Index) -> Element {
        self.innerSet[position]
    }

    public func index(after i: Set<Element>.Index) -> Set<Element>.Index {
        self.innerSet.index(after: i)
    }

    public func formIndex(after i: inout Set<Element>.Index) {
        self.innerSet.formIndex(after: &i)
    }

    public func firstIndex(of member: Element) -> Set<Element>.Index? {
        self.innerSet.firstIndex(of: member)
    }

    public var count: Int {
        self.innerSet.count
    }

    public var isEmpty: Bool {
        self.innerSet.isEmpty
    }
    public var indices: DefaultIndices<Set<Element>> {
        self.innerSet.indices
    }

    public static func ==(lhs: HashSet<Element>, rhs: HashSet<Element>) -> Bool {
        lhs.innerSet == rhs.innerSet
    }

    public static func ==(lhs: HashSet<Element>, rhs: Set<Element>) -> Bool {
        lhs.innerSet == rhs
    }


    public func hash(into hasher: inout Hasher) {
        innerSet.hash(into: &hasher)
    }

    public var hashValue: Int {
        innerSet.hashValue
    }


    public var customMirror: Mirror {
        innerSet.customMirror
    }
    public var description: String {
        innerSet.description
    }

    public var debugDescription: String {
        innerSet.debugDescription
    }

    public func add(_ newMember: Element) {
        self.insert(newMember)
    }

    @discardableResult
    public func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element) {
        innerSet.insert(newMember)
    }

    public func update(with newMember: Element) -> Element? {
        innerSet.update(with: newMember)
    }

    public func remove(_ member: Element) -> Element? {
        innerSet.remove(member)
    }

    public func remove(at position: Set<Element>.Index) -> Element {
        innerSet.remove(at: position)
    }

    public func removeAll(keepingCapacity keepCapacity: Bool = false) {
        innerSet.removeAll(keepingCapacity: keepCapacity)
    }

    public func removeFirst() -> Element {
        innerSet.removeFirst()
    }


    public init<Source>(_ sequence: Source) where Element == Source.Element, Source: Sequence {
        innerSet.reserveCapacity(sequence.underestimatedCount + 8)
        for e in sequence {
            innerSet.add(e)
        }
    }

    public func isSubset<S>(of possibleSuperset: S) -> Bool where Element == S.Element, S: Sequence {
        innerSet.isSubset(of: possibleSuperset)
    }

    public func isStrictSubset<S>(of possibleStrictSuperset: S) -> Bool where Element == S.Element, S: Sequence {
        innerSet.isStrictSubset(of: possibleStrictSuperset)
    }

    public func isSuperset<S>(of possibleSubset: S) -> Bool where Element == S.Element, S: Sequence {
        innerSet.isSuperset(of: possibleSubset)
    }

    public func isStrictSuperset<S>(of possibleStrictSubset: S) -> Bool where Element == S.Element, S: Sequence {
        innerSet.isStrictSubset(of: possibleStrictSubset)
    }

    public func isDisjoint<S>(with other: S) -> Bool where Element == S.Element, S: Sequence {
        innerSet.isDisjoint(with: other)
    }

    public func union<S>(_ other: S) -> HashSet<Element> where Element == S.Element, S: Sequence {
        HashSet(innerSet.union(other))
    }

    public func formUnion<S>(_ other: S) where Element == S.Element, S: Sequence {
        innerSet.formUnion(other)
    }

    public func subtracting<S>(_ other: S) -> HashSet<Element> where Element == S.Element, S: Sequence {
        HashSet(innerSet.subtracting(other))
    }

    public func subtract<S>(_ other: S) where Element == S.Element, S: Sequence {
        innerSet.subtract(other)
    }

    public func intersection<S>(_ other: S) -> HashSet<Element> where Element == S.Element, S: Sequence {
        HashSet(innerSet.intersection(other))
    }

    public func formIntersection<S>(_ other: S) where Element == S.Element, S: Sequence {
        innerSet.formIntersection(other)
    }

    public func symmetricDifference<S>(_ other: S) -> HashSet<Element> where Element == S.Element, S: Sequence {
        HashSet(innerSet.symmetricDifference(other))
    }

    public func formSymmetricDifference<S>(_ other: S) where Element == S.Element, S: Sequence {
        innerSet.formSymmetricDifference(other)
    }
}

public extension HashSet {
    func popFirst() -> Element? {
        innerSet.popFirst()
    }

    var capacity: Int {
        innerSet.capacity
    }

    func reserveCapacity(_ minimumCapacity: Int) {
        innerSet.reserveCapacity(minimumCapacity)
    }
}

public extension HashSet {

    func subtract(_ other: HashSet<Element>) {
        innerSet.subtract(other.innerSet)
    }

    func isSubset(of other: HashSet<Element>) -> Bool {
        innerSet.isSubset(of: other.innerSet)
    }

    func isSuperset(of other: HashSet<Element>) -> Bool {
        innerSet.isSuperset(of: other.innerSet)
    }

    func isDisjoint(with other: HashSet<Element>) -> Bool {
        innerSet.isDisjoint(with: other.innerSet)
    }

    func subtracting(_ other: HashSet<Element>) -> HashSet<Element> {
        HashSet(innerSet.subtracting(other.innerSet))
    }

    func isStrictSuperset(of other: HashSet<Element>) -> Bool {
        innerSet.isStrictSubset(of: other.innerSet)
    }

    func isStrictSubset(of other: HashSet<Element>) -> Bool {
        innerSet.isStrictSubset(of: other.innerSet)
    }

    func intersection(_ other: HashSet<Element>) -> HashSet<Element> {
        HashSet(innerSet.intersection(other.innerSet))
    }

    func formSymmetricDifference(_ other: HashSet<Element>) {
        innerSet.formSymmetricDifference(other.innerSet)
    }

}

